package conf

import (
	"encoding/json"

	"chainmaker.org/chainmaker/smarteditor/common"
	"chainmaker.org/chainmaker/smarteditor/db"
	"github.com/jinzhu/gorm"
)

type CompileInfoModel struct {
	UserId       string `gorm:"column:user_id;unique_index:uid_c;index:uid_src;index:uid_bin;index:uid_ts"`
	ContractName string `gorm:"column:contract;unique_index:uid_c"`
	SrcMd5       string `gorm:"column:src_md5;index:uid_src;index:uid_src"`
	BinMd5       string `gorm:"column:bin_md5;index:uid_bin"`
	BuildTime    int64  `gorm:"column:build_time;index:uid_ts"`
	// CreatedAt    int64  `gorm:"column:created_at"`
	// UpdatedAt    int64  `gorm:"column:updated_at"`
	Host        string   `gorm:"column:host"`
	Path        string   `gorm:"column:path;size:1024"` // build 下的 7z文件
	Methods     []string `gorm:"-"`
	MethodsInDB string   `gorm:"column:methods;type:text"`
}

func (*CompileInfoModel) TableName() string {
	return "compile_infos"
}

// GetCompileList 根据用户id,分页查询已编译程序, buildTime为上一页最后一条数据的时间戳
func GetCompileList(userId string, page, pageSize int64) ([]CompileInfoModel, int, error) {
	var total int
	var retList []CompileInfoModel
	totalErr := db.GlobalDB.Model(&CompileInfoModel{}).Where("user_id = ?", userId).Count(&total).Error
	if totalErr != nil {
		log.Errorf("GetCompileList count userId %s failed %s", userId, totalErr.Error())
		return retList, total, totalErr
	}
	queryDB := db.GlobalDB.Model(&CompileInfoModel{}).Where("user_id = ?", userId)
	var queryErr error
	if pageSize == -1 {
		queryErr = queryDB.Order("build_time desc").Scan(&retList).Error
	} else {
		queryErr = queryDB.Order("build_time desc").Limit(pageSize).Offset((page - 1) * pageSize).Scan(&retList).Error
	}

	if queryErr != nil {
		log.Errorf("GetCompileList userId %s, failed %s", userId, queryErr.Error())
		return retList, total, queryErr
	}
	for i := 0; i < len(retList); i++ {
		unMarshalErr := json.Unmarshal([]byte(retList[i].MethodsInDB), &retList[i].Methods)
		if unMarshalErr != nil {
			log.Errorf("GetCompileList unmarshal failed %s", unMarshalErr.Error())
			continue
		}
	}
	return retList, total, nil
}

// DeleteCompileList 根据用户id和合约名称,删除数据库记录
func DeleteCompileInfo(userId string, contractName string) error {
	return db.GlobalDB.Model(&CompileInfoModel{}).Where("user_id = ?", userId).Where("contract = ?", contractName).Delete(&CompileInfoModel{}).Error
}

// SaveCompileInfo 保存编译信息
func SaveCompileInfo(data *CompileInfoModel) error {
	methodsBs, marshalErr := json.Marshal(data.Methods)
	if marshalErr != nil {
		log.Errorf("SaveCompileInfo marshal [%+v] ,failed %s", *data, marshalErr.Error())
		return marshalErr
	}
	data.MethodsInDB = string(methodsBs)
	data.Host = common.UniqueHost //机器唯一编号
	var dataInDb CompileInfoModel
	queryErr := db.GlobalDB.Model(&CompileInfoModel{}).Where("user_id = ?", data.UserId).Where("contract = ?", data.ContractName).First(&dataInDb).Error
	if queryErr != nil {
		if gorm.IsRecordNotFoundError(queryErr) {
			return db.GlobalDB.Model(&CompileInfoModel{}).Create(data).Error
		}
		log.Errorf("SaveCompileInfo data [%+v], failed %s", *data, queryErr.Error())
		return queryErr
	}
	return db.GlobalDB.Model(&CompileInfoModel{}).Where("user_id = ?", data.UserId).Where("contract = ?", data.ContractName).
		Update("src_md5 = ?", data.SrcMd5).Update("bin_md5 = ?", data.BinMd5).
		Update("build_time = ?", data.BuildTime).Update("host = ?", data.Host).
		Update("path = ?", data.Path).Update("methods = ?", data.MethodsInDB).Error
}

func GetCompileInfo(userId string, contractName string) (*CompileInfoModel, error) {
	var dataInDb CompileInfoModel
	queryErr := db.GlobalDB.Model(&CompileInfoModel{}).Where("user_id = ?", userId).Where("contract = ?", contractName).First(&dataInDb).Error
	if queryErr != nil {
		return &dataInDb, queryErr
	}
	unmarshalErr := json.Unmarshal([]byte(dataInDb.MethodsInDB), &(dataInDb.Methods))
	return &dataInDb, unmarshalErr
}

func GetvCompileByDeployInfo(srcmd5 string, binmd5 string) (*CompileInfoModel, error) {
	var dataInDb CompileInfoModel
	queryErr := db.GlobalDB.Model(&CompileInfoModel{}).Where("src_md5 = ?", srcmd5).Where("bin_md5 = ?", binmd5).First(&dataInDb).Error
	if queryErr != nil {
		return &dataInDb, queryErr
	}
	unmarshalErr := json.Unmarshal([]byte(dataInDb.MethodsInDB), &(dataInDb.Methods))
	return &dataInDb, unmarshalErr
}
